﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace myCompiler
{
    public class BasicAction
    {
        protected CompilerWorker worker = CompilerWorker.GetInstance();
        public string MethodName { get; set; }
        public virtual void EmitCode(TypeBuilder myTypeBldr)
        {
        }
    }

    public class SetStringAction : BasicAction
    {
        public string ValName { get; set; }
        public string ValValue { get; set; }

        public SetStringAction(ValueType valName, ValueType valValue)
        {
            this.worker.AddMessage("do action set string");
            this.ValName = valName.valname;
            this.ValValue = valValue.str;
            worker.syntaxTree.SymbolTable.Add(new SymbolItem(ValName,ValValue,SymbolType.TypeString));
        }

        public override void EmitCode(TypeBuilder myTypeBldr)
        {
            this.worker.AddMessage("emit code set sting");
            FieldBuilder xField = myTypeBldr.DefineField(this.ValName, typeof (string), FieldAttributes.Private);
            this.MethodName = "SetStringAction_" + this.ValName;
            MethodBuilder methodBuilder = myTypeBldr.DefineMethod(MethodName,
                                                                  MethodAttributes.Public, typeof (void),
                                                                  new Type[] {});
            var MILG = methodBuilder.GetILGenerator();
            MILG.Emit(OpCodes.Ldarg_0);
            MILG.Emit(OpCodes.Ldstr, this.ValValue);
            MILG.Emit(OpCodes.Stfld, xField);
            MILG.Emit(OpCodes.Nop);
            MILG.Emit(OpCodes.Ret);
        }
    }

    public class SetNumberAction : BasicAction
    {
        public string ValName { get; set; }
        public Double ValValue { get; set; }

        public SetNumberAction(ValueType valName, ValueType valValue)
        {
            this.worker.AddMessage("do action set number");
            this.ValName = valName.valname;
            this.ValValue = valValue.num;
            worker.syntaxTree.SymbolTable.Add(new SymbolItem(ValName, ValValue.ToString(), SymbolType.TypeDouble));
        }

        public override void EmitCode(TypeBuilder myTypeBldr)
        {
            this.worker.AddMessage("emit code set number");
            FieldBuilder xField = myTypeBldr.DefineField(this.ValName, typeof (int), FieldAttributes.Private);
            this.MethodName = "SetNumberAction_" + this.ValName;
            MethodBuilder methodBuilder = myTypeBldr.DefineMethod(MethodName,
                                                                  MethodAttributes.Public, typeof (void),
                                                                  new Type[] {});
            var MILG = methodBuilder.GetILGenerator();
            MILG.Emit(OpCodes.Ldarg_0);
            MILG.Emit(OpCodes.Ldc_R8, this.ValValue);
            MILG.Emit(OpCodes.Stfld, xField);
            MILG.Emit(OpCodes.Nop);
            MILG.Emit(OpCodes.Ret);
        }
    }

    public class ScreenOutAction : BasicAction
    {
        public string ValValue { get; set; }

        public ScreenOutAction(ValueType valString)
        {
            this.worker.AddMessage("do action screen out");
            this.ValValue = valString.str;
        }
        public override void EmitCode(TypeBuilder myTypeBldr)
        {
            this.MethodName = "ScreenOutAction";
        }
    }

    public class ScreenOutValAction:BasicAction
    {
        public string ValValue { get; set; }
        public ScreenOutValAction(ValueType valName)
        {
            this.worker.AddMessage("do action variable screen out");
            this.ValValue = valName.valname;
        }
        public override void EmitCode(TypeBuilder myTypeBldr)
        {
            this.MethodName = "ScreenOutValAction";
        }
    }
}